]> git.openstreetmap.org Git - rails.git/blob - vendor/plugins/rails-i18n/tools/Rails I18n.tmbundle/Support/lib/dictionary.rb
First stage of i18n. Some migrations and extra plugins.
[rails.git] / vendor / plugins / rails-i18n / tools / Rails I18n.tmbundle / Support / lib / dictionary.rb
1 # = Dictionary
2 #
3 # The Dictionary class is a Hash that preserves order.
4 # So it has some array-like extensions also. By defualt
5 # a Dictionary object preserves insertion order, but any
6 # order can be specified including alphabetical key order.
7 #
8 # == Usage
9 #
10 # Just require this file and use Dictionary instead of Hash.
11 #
12 #   # You can do simply
13 #   hsh = Dictionary.new
14 #   hsh['z'] = 1
15 #   hsh['a'] = 2
16 #   hsh['c'] = 3
17 #   p hsh.keys     #=> ['z','a','c']
18 #
19 #   # or using Dictionary[] method
20 #   hsh = Dictionary['z', 1, 'a', 2, 'c', 3]
21 #   p hsh.keys     #=> ['z','a','c']
22 #
23 #   # but this don't preserve order
24 #   hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3]
25 #   p hsh.keys     #=> ['a','c','z']
26 #
27 #   # Dictionary has useful extensions: push, pop and unshift
28 #   p hsh.push('to_end', 15)       #=> true, key added
29 #   p hsh.push('to_end', 30)       #=> false, already - nothing happen
30 #   p hsh.unshift('to_begin', 50)  #=> true, key added
31 #   p hsh.unshift('to_begin', 60)  #=> false, already - nothing happen
32 #   p hsh.keys                     #=> ["to_begin", "a", "c", "z", "to_end"]
33 #   p hsh.pop                      #=> ["to_end", 15], if nothing remains, return nil
34 #   p hsh.keys                     #=> ["to_begin", "a", "c", "z"]
35 #   p hsh.shift                    #=> ["to_begin", 30], if nothing remains, return nil
36 #
37 # == Usage Notes
38 #
39 # * You can use #order_by to set internal sort order.
40 # * #<< takes a two element [k,v] array and inserts.
41 # * Use ::auto which creates Dictionay sub-entries as needed.
42 # * And ::alpha which creates a new Dictionary sorted by key.
43 #
44 # == Authors
45 #
46 # * Jan Molic
47 # * Thomas Sawyer
48 #
49 # == Acknowledgments
50 #
51 # * Andrew Johnson (merge, to_a, inspect, shift and Hash[])
52 # * Jeff Sharpe    (reverse and reverse!)
53 # * Thomas Leitner (has_key? and key?)
54 #
55 # Originally ported from OrderHash 2.0, Copyright (c) 2005 jan molic
56 #
57 # == History
58 #
59 # * 2007.10.31 trans
60 # ** Fixed initialize so the constructor blocks correctly effected dictionary rather then just the internal hash.
61 #
62 # == Copying
63 #
64 # Copyright (c) 2005 Jan Molic, Thomas Sawyer
65 #
66 # Ruby License
67 #
68 # This module is free software. You may use, modify, and/or redistribute this
69 # software under the same terms as Ruby.
70 #
71 # This program is distributed in the hope that it will be useful, but WITHOUT
72 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
73 # FOR A PARTICULAR PURPOSE.
74
75
76 # = Dictionary
77 #
78 # The Dictionary class is a Hash that preserves order.
79 # So it has some array-like extensions also. By defualt
80 # a Dictionary object preserves insertion order, but any
81 # order can be specified including alphabetical key order.
82 #
83 # == Usage
84 #
85 # Just require this file and use Dictionary instead of Hash.
86 #
87 #   # You can do simply
88 #   hsh = Dictionary.new
89 #   hsh['z'] = 1
90 #   hsh['a'] = 2
91 #   hsh['c'] = 3
92 #   p hsh.keys     #=> ['z','a','c']
93 #
94 #   # or using Dictionary[] method
95 #   hsh = Dictionary['z', 1, 'a', 2, 'c', 3]
96 #   p hsh.keys     #=> ['z','a','c']
97 #
98 #   # but this don't preserve order
99 #   hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3]
100 #   p hsh.keys     #=> ['a','c','z']
101 #
102 #   # Dictionary has useful extensions: push, pop and unshift
103 #   p hsh.push('to_end', 15)       #=> true, key added
104 #   p hsh.push('to_end', 30)       #=> false, already - nothing happen
105 #   p hsh.unshift('to_begin', 50)  #=> true, key added
106 #   p hsh.unshift('to_begin', 60)  #=> false, already - nothing happen
107 #   p hsh.keys                     #=> ["to_begin", "a", "c", "z", "to_end"]
108 #   p hsh.pop                      #=> ["to_end", 15], if nothing remains, return nil
109 #   p hsh.keys                     #=> ["to_begin", "a", "c", "z"]
110 #   p hsh.shift                    #=> ["to_begin", 30], if nothing remains, return nil
111 #
112 # == Usage Notes
113 #
114 # * You can use #order_by to set internal sort order.
115 # * #<< takes a two element [k,v] array and inserts.
116 # * Use ::auto which creates Dictionay sub-entries as needed.
117 # * And ::alpha which creates a new Dictionary sorted by key.
118 #
119 class Dictionary
120
121   include Enumerable
122
123   class << self
124     #--
125     # TODO is this needed? Doesn't the super class do this?
126     #++
127
128     def [](*args)
129       hsh = new
130       if Hash === args[0]
131         hsh.replace(args[0])
132       elsif (args.size % 2) != 0
133         raise ArgumentError, "odd number of elements for Hash"
134       else
135         while !args.empty?
136           hsh[args.shift] = args.shift
137         end
138       end
139       hsh
140     end
141
142     # Like #new but the block sets the order.
143     #
144     def new_by(*args, &blk)
145       new(*args).order_by(&blk)
146     end
147
148     # Alternate to #new which creates a dictionary sorted by key.
149     #
150     #   d = Dictionary.alpha
151     #   d["z"] = 1
152     #   d["y"] = 2
153     #   d["x"] = 3
154     #   d  #=> {"x"=>3,"y"=>2,"z"=>2}
155     #
156     # This is equivalent to:
157     #
158     #   Dictionary.new.order_by { |key,value| key }
159
160     def alpha(*args, &block)
161       new(*args, &block).order_by_key
162     end
163
164     # Alternate to #new which auto-creates sub-dictionaries as needed.
165     #
166     #   d = Dictionary.auto
167     #   d["a"]["b"]["c"] = "abc"  #=> { "a"=>{"b"=>{"c"=>"abc"}}}
168     #
169     def auto(*args)
170       #AutoDictionary.new(*args)
171       leet = lambda { |hsh, key| hsh[key] = new(&leet) }
172       new(*args, &leet)
173     end
174   end
175
176    # New Dictiionary.
177
178   def initialize(*args, &blk)
179     @order = []
180     @order_by = nil
181     if blk
182       dict = self                                  # This ensure autmatic key entry effect the
183       oblk = lambda{ |hsh, key| blk[dict,key] }    # dictionary rather then just the interal hash.
184       @hash = Hash.new(*args, &oblk)
185     else
186       @hash = Hash.new(*args)
187     end
188   end
189
190   def order
191     reorder if @order_by
192     @order
193   end
194
195   # Keep dictionary sorted by a specific sort order.
196
197   def order_by( &block )
198     @order_by = block
199     order
200     self
201   end
202
203   # Keep dictionary sorted by key.
204   #
205   #   d = Dictionary.new.order_by_key
206   #   d["z"] = 1
207   #   d["y"] = 2
208   #   d["x"] = 3
209   #   d  #=> {"x"=>3,"y"=>2,"z"=>2}
210   #
211   # This is equivalent to:
212   #
213   #   Dictionary.new.order_by { |key,value| key }
214   #
215   # The initializer Dictionary#alpha also provides this.
216
217   def order_by_key
218     @order_by = lambda { |k,v| k }
219     order
220     self
221   end
222
223   # Keep dictionary sorted by value.
224   #
225   #   d = Dictionary.new.order_by_value
226   #   d["z"] = 1
227   #   d["y"] = 2
228   #   d["x"] = 3
229   #   d  #=> {"x"=>3,"y"=>2,"z"=>2}
230   #
231   # This is equivalent to:
232   #
233   #   Dictionary.new.order_by { |key,value| value }
234
235   def order_by_value
236     @order_by = lambda { |k,v| v }
237     order
238     self
239   end
240
241   #
242
243   def reorder
244     if @order_by
245       assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
246       @order = assoc.collect{ |k,v| k }
247     end
248     @order
249   end
250
251   #def ==( hsh2 )
252   #  return false if @order != hsh2.order
253   #  super hsh2
254   #end
255
256   def ==(hsh2)
257     if hsh2.is_a?( Dictionary )
258       @order == hsh2.order &&
259       @hash  == hsh2.instance_variable_get("@hash")
260     else
261       false
262     end
263   end
264
265   def [] k
266     @hash[ k ]
267   end
268
269   def fetch(k, *a, &b)
270     @hash.fetch(k, *a, &b)
271   end
272
273   # Store operator.
274   #
275   #   h[key] = value
276   #
277   # Or with additional index.
278   #
279   #  h[key,index] = value
280
281   def []=(k, i=nil, v=nil)
282     if v
283       insert(i,k,v)
284     else
285       store(k,i)
286     end
287   end
288
289   def insert( i,k,v )
290     @order.insert( i,k )
291     @hash.store( k,v )
292   end
293
294   def store( a,b )
295     @order.push( a ) unless @hash.has_key?( a )
296     @hash.store( a,b )
297   end
298
299   def clear
300     @order = []
301     @hash.clear
302   end
303
304   def delete( key )
305     @order.delete( key )
306     @hash.delete( key )
307   end
308
309   def each_key
310     order.each { |k| yield( k ) }
311     self
312   end
313
314   def each_value
315     order.each { |k| yield( @hash[k] ) }
316     self
317   end
318
319   def each
320     order.each { |k| yield( k,@hash[k] ) }
321     self
322   end
323   alias each_pair each
324
325   def delete_if
326     order.clone.each { |k| delete k if yield(k,@hash[k]) }
327     self
328   end
329
330   def values
331     ary = []
332     order.each { |k| ary.push @hash[k] }
333     ary
334   end
335
336   def keys
337     order
338   end
339
340   def invert
341     hsh2 = self.class.new
342     order.each { |k| hsh2[@hash[k]] = k }
343     hsh2
344   end
345
346   def reject(&block)
347     self.dup.delete_if(&block)
348   end
349
350   def reject!( &block )
351     hsh2 = reject(&block)
352     self == hsh2 ? nil : hsh2
353   end
354
355   def replace( hsh2 )
356     @order = hsh2.order
357     @hash = hsh2.hash
358   end
359
360   def shift
361     key = order.first
362     key ? [key,delete(key)] : super
363   end
364
365   def unshift( k,v )
366     unless @hash.include?( k )
367       @order.unshift( k )
368       @hash.store( k,v )
369       true
370     else
371       false
372     end
373   end
374
375   def <<(kv)
376     push(*kv)
377   end
378
379   def push( k,v )
380     unless @hash.include?( k )
381       @order.push( k )
382       @hash.store( k,v )
383       true
384     else
385       false
386     end
387   end
388
389   def pop
390     key = order.last
391     key ? [key,delete(key)] : nil
392   end
393
394   def inspect
395     ary = []
396     each {|k,v| ary << k.inspect + "=>" + v.inspect}
397     '{' + ary.join(", ") + '}'
398   end
399
400   def dup
401     a = []
402     each{ |k,v| a << k; a << v }
403     self.class[*a]
404   end
405
406   def update( hsh2 )
407     hsh2.each { |k,v| self[k] = v }
408     reorder
409     self
410   end
411   alias :merge! update
412
413   def merge( hsh2 )
414     self.dup.update(hsh2)
415   end
416
417   def select
418     ary = []
419     each { |k,v| ary << [k,v] if yield k,v }
420     ary
421   end
422
423   def reverse!
424     @order.reverse!
425     self
426   end
427
428   def reverse
429     dup.reverse!
430   end
431
432   #
433   def first(x=nil)
434     return @hash[order.first] unless x
435     order.first(x).collect { |k| @hash[k] }
436   end
437
438   #
439   def last(x=nil)
440     return @hash[order.last] unless x
441     order.last(x).collect { |k| @hash[k] }
442   end
443
444   def length
445     @order.length
446   end
447   alias :size :length
448
449   def empty?
450     @hash.empty?
451   end
452
453   def has_key?(key)
454     @hash.has_key?(key)
455   end
456
457   def key?(key)
458     @hash.key?(key)
459   end
460
461   def to_a
462     ary = []
463     each { |k,v| ary << [k,v] }
464     ary
465   end
466
467   def to_s
468     self.to_a.to_s
469   end
470
471   def to_hash
472     @hash.dup
473   end
474
475   def to_h
476     @hash.dup
477   end
478 end